Skip to content

fix(channels): restrict private-channel invitations - #4612

Merged
wesbillman merged 2 commits into
mainfrom
codex/security-private-channel-invite-authority
Aug 5, 2026
Merged

fix(channels): restrict private-channel invitations#4612
wesbillman merged 2 commits into
mainfrom
codex/security-private-channel-invite-authority

Conversation

@jmecom

@jmecom jmecom commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

This change requires an active owner or administrator for third-party additions to private channels. The relay validator and transactional database authority enforce the same rule, including removed-member reactivation and role-change paths.

Idempotent self-target behavior remains available, while ordinary members can no longer extend private-channel access to another identity.

Testing

  • git diff --check origin/main...codex/security-private-channel-invite-authority
  • Rebased onto origin/main at 5c98932
  • Full CI pending

Originating Buzz thread: buzz://message?channel=3928fe05-df61-4b5d-b9c7-d623b9b10ea1&id=3c6c02312f763fbe0d2bfc33a6c1a362f91d0354f3d18b039cf7a0558c1439d1

@jmecom
jmecom marked this pull request as ready for review August 3, 2026 21:00
@jmecom
jmecom requested a review from a team as a code owner August 3, 2026 21:00
Require an active owner or admin for third-party private-channel additions in both relay validation and the transactional database authority. Preserve idempotent self-targeting.

Co-authored-by: Jordan Mecom <jm@squareup.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
Signed-off-by: Eli Foster <efoster@squareup.com>
@elifoster-block
elifoster-block force-pushed the codex/security-private-channel-invite-authority branch from 378c643 to f428577 Compare August 4, 2026 18:31
elifoster-block
elifoster-block previously approved these changes Aug 4, 2026

@elifoster-block elifoster-block left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client-side follow-up to Jordan's commits: hide the "add people" and invite buttons when you're not an owner/admin of a private channel, and stop mobile from silently dropping your message when the relay refuses the add.

@elifoster-block
elifoster-block force-pushed the codex/security-private-channel-invite-authority branch from f428577 to e938a8f Compare August 4, 2026 18:54
The relay now rejects a plain member adding another identity to a private
channel, but both clients still offered the affordance:

- Desktop's members sidebar showed "Add people" to any member, and the
  non-member mention dialog always offered Invite. Both now consult a shared
  `canAddChannelMembers` mirror of the relay's kind:9000 authority, and the
  sidebar explains why the add is unavailable instead of hiding it silently.
- Mobile's mention prompt was the only invite path and had no gate at all.
  `addMembers` also threw out of an `unawaited(send())`, so a relay rejection
  vanished: the message was never sent and nothing was shown. It now collects
  per-pubkey failures, always invalidates the members cache, and reports them
  via `AddMembersException`; the composer surfaces add and send failures in a
  SnackBar, keeps the draft, and demotes un-added mentions to reference tags
  so the message still goes out.

Also updates VISION.md, which still documented private channels as
"invited by member", and records why the self-target escape hatch in
`add_member` / `validate_admin_event` is not a role-escalation hole.

Tests: unit coverage for both capability mirrors, a mobile widget test for the
private-channel agent-add skip, plus e2e coverage that an admin can still
invite and that a self-targeted re-add stays idempotent.

Signed-off-by: Eli Foster <efoster@squareup.com>
@elifoster-block
elifoster-block force-pushed the codex/security-private-channel-invite-authority branch from e938a8f to 7364c7d Compare August 4, 2026 19:04

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security review by Carl, acting on Wes’s behalf.

I found no blocking issue at head 7364c7d77353234aa468535054876d4471929836.

The authorization boundary is enforced twice and the database remains authoritative. The relay validator rejects a private-channel third-party add unless the signed actor is an active owner/admin, giving clients an immediate rejection. buzz_db::channel::add_member repeats the check inside the existing per-channel advisory-locked transaction, so alternate callers and role/removal races cannot bypass it.

I traced the self-target exception. It only preserves an active member’s idempotent re-add: a non-member/soft-removed identity fails the active-role lookup, and an active member cannot use it to change role because the separate role-change guard requires owner/admin. Private kind:9021 self-join remains rejected before this path.

Owner/admin additions, creator bootstrap, open-channel behavior, and existing huddle/ephemeral flows remain intact. Desktop and mobile mirror the authority only for UX; the relay/DB checks do not trust client state. Mobile now reports partial add failures and demotes identities that were not added to non-notifying reference mentions rather than silently losing the message.

Tests cover regular-member denial, admin invitation, idempotent self-targeting, client capability mirrors, and the mobile rejected-add flow. Exact-head CI is green, including Rust/unit, mobile, security, desktop and relay/backend E2E, cross-compiles, DCO, Semgrep, and zizmor.

Expected behavior change: ordinary members can no longer invite others into private channels. That is the intended security fix, not a regression.

@wesbillman
wesbillman merged commit efe1893 into main Aug 5, 2026
33 checks passed
@wesbillman
wesbillman deleted the codex/security-private-channel-invite-authority branch August 5, 2026 17:47
tlongwell-block pushed a commit that referenced this pull request Aug 5, 2026
Pull main in before remediation, per Tyler's instruction: no rebase, no
force, new commits on top.

Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
Signed-off-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>

* origin/main:
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  fix(agent): recover from unsupported image input instead of poisoning the turn (#4896)
  Define private managed agent wire protocol (#4593)
  fix(mobile): serialize channel sections sync (#3165)
  fix(desktop): make missing-command error actionable for released builds (#4802)

Signed-off-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
wpfleger96 pushed a commit that referenced this pull request Aug 5, 2026
…-overflow-recovery

* origin/main:
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  fix(agent): recover from unsupported image input instead of poisoning the turn (#4896)
  Define private managed agent wire protocol (#4593)
  fix(mobile): serialize channel sections sync (#3165)
  fix(desktop): make missing-command error actionable for released builds (#4802)
  chore(release): release Buzz Desktop version 0.5.5 (#4809)
  feat: paste composer text without formatting (#4801)
  Revert "chore(release): release Buzz Desktop version 0.5.5" (#4808)
  chore(release): release Buzz Desktop version 0.5.5 (#4800)

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	crates/buzz-agent/src/agent.rs
#	crates/buzz-agent/src/handoff.rs
#	crates/buzz-agent/src/types.rs
#	crates/buzz-agent/tests/regressions.rs
atishpatel added a commit that referenced this pull request Aug 5, 2026
…usage

* origin/main:
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)

Co-authored-by: Atish Patel <atish@squareup.com>
Signed-off-by: Atish Patel <atish@squareup.com>
wpfleger96 pushed a commit that referenced this pull request Aug 5, 2026
…arer-auth

* origin/main: (65 commits)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  fix(agent): recover from unsupported image input instead of poisoning the turn (#4896)
  Define private managed agent wire protocol (#4593)
  fix(mobile): serialize channel sections sync (#3165)
  fix(desktop): make missing-command error actionable for released builds (#4802)
  ...

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	CHANGELOG.md
atishpatel added a commit that referenced this pull request Aug 5, 2026
…usage

* origin/main:
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)

Co-authored-by: Atish Patel <atish@squareup.com>
Signed-off-by: Atish Patel <atish@squareup.com>
wpfleger96 pushed a commit that referenced this pull request Aug 5, 2026
…ed-agent-store-merge

* origin/main: (24 commits)
  fix(reactions): support max-length custom emoji (#3833)
  feat(desktop): allow leaving your final community (#3621)
  fix(buzz-agent): recover from context-window 400s instead of sticking (#4946)
  docs(persona-pack): fix stale desktop import instructions (#4500)
  fix(desktop): route macos notification clicks (#4799)
  feat(mobile): sync themes per community (#3767)
  feat(desktop): sync themes per community (#3653)
  feat(desktop): cap OpenClaw agent parallelism at 5 (#4019)
  fix(buzz-agent): scope handoff cap per turn, not per session lifetime (#4805)
  Fix mobile message timeline bounce (#4862)
  Polish mobile bottom sheets and profile cards (#4911)
  Fix media attachment actions (#4849)
  fix(desktop): remove join API token control (#4897)
  fix(desktop): allow shared agent mentions (#4913)
  Polish mobile top navigation (#4778)
  fix(release): tag immutable desktop candidates (#4811)
  fix(channels): restrict private-channel invitations (#4612)
  fix(acp): reject unattended permission requests (#4609)
  fix(workflow): bind trigger author to the signed event (#4607)
  fix(git): revoke access for banned relay members (#4608)
  ...

Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>

# Conflicts:
#	desktop/src-tauri/src/managed_agents/runtime.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants